#ifndef __SERVICE__
#define __SERVICE__

#ifdef _WIN32
#include <WinSock2.h>
#include <windows.h>
#include <stdio.h>
#else 
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#endif

#define SERVICE_PORT 5202  //服务端端口号(必须和discover.h中的BROADCAST_PORT相同)

#ifdef _WIN32
// 服务模式(持续接收UDP探测报文并响应当前设备信息)
void Service()
{
    // 1、创建UDP套接字
    SOCKET sockfd =socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
    if(sockfd==INVALID_SOCKET)
	{
		perror("UdpSock create failed");
		exit(1);
	}

    //2、绑定套接字
    SOCKADDR_IN servAddr;
	memset(&servAddr, 0, sizeof(servAddr));
	servAddr.sin_family = AF_INET;
	servAddr.sin_addr.s_addr = INADDR_ANY;
	servAddr.sin_port = htons(SERVICE_PORT);

	if (bind(sockfd, (SOCKADDR*)&servAddr, sizeof(servAddr)) == SOCKET_ERROR)
	{
		perror("UdpSock bind failed");
		exit(1);
	}

    // 3、持续接收探测报文并进行响应
    while (1)
    {
        SOCKADDR_IN fromaddr;
        memset(&fromaddr, 0, sizeof(fromaddr));
        int addrlen = sizeof(fromaddr);

        // 阻塞式读取报文
        char recvbuf[1024] = {0};
        int msglen = recvfrom(sockfd,recvbuf, sizeof(recvbuf) - 1, 0, (sockaddr *)&fromaddr, &addrlen);

        if(msglen<=0)//读取出错，停止读取，然后关闭套接字
        break;

        //读取成功
        recvbuf[msglen] = 0;
        //printf("got a message: %s\n",recvbuf);
        if (strcmp(recvbuf,"TYPE:DISCOVER_REQUEST")==0) // 是探测报文
        {
            printf("got a divice request: %s\n",recvbuf);
            // 获取当前设备信息，并组织成响应发送给探测方
            char deviceName[256]={0};//设备名称
            gethostname(deviceName, sizeof(deviceName));
            // 响应报文的格式应该为：TYPE:DISCOVER_RESPONSE DIVICE_NAME:NAME
            char resp[256]={0};
            snprintf(resp,sizeof(resp)-1,"TYPE:DISCOVER_RESPONSE DIVICE_NAME:%s",deviceName);

            if(sendto(sockfd, resp, strlen(resp), 0, (sockaddr *)&fromaddr, addrlen)!=strlen(resp))//发送出错，停止读取，然后关闭套接字
            break;
        }
        // 不是探测报文，直接忽略
    }

    closesocket(sockfd);
}

#else //linux
// 服务模式(持续接收UDP探测报文并响应当前设备信息)
void Service()
{
    // 1、创建UDP套接字
    int sockfd =socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
    if(sockfd<0)
	{
		perror("UdpSock create failed");
		exit(1);
	}

    //2、绑定套接字
    struct sockaddr_in servAddr;
	memset(&servAddr, 0, sizeof(servAddr));
	servAddr.sin_family = AF_INET;
	servAddr.sin_addr.s_addr = INADDR_ANY;
	servAddr.sin_port = htons(SERVICE_PORT);

	if (bind(sockfd, (struct sockaddr *)&servAddr, sizeof(servAddr))<0)
	{
		perror("UdpSock bind failed");
		exit(1);
	}

    // 3、持续接收探测报文并进行响应
    while (1)
    {
        struct sockaddr_in fromaddr;
        memset(&fromaddr, 0, sizeof(fromaddr));
        socklen_t  addrlen = sizeof(fromaddr);

        // 阻塞式读取报文
        char recvbuf[1024] = {0};
        int  msglen = recvfrom(sockfd,recvbuf, sizeof(recvbuf) - 1, 0, (struct sockaddr *)&fromaddr, &addrlen);

        if(msglen<=0)//读取出错，停止读取，然后关闭套接字
        break;

        //读取成功
        recvbuf[msglen] = 0;
        if (strcmp(recvbuf,"TYPE:DISCOVER_REQUEST")==0) // 是探测报文
        {
            // 获取当前设备名称，并组织成响应发送给探测方
            char deviceName[256]={0};
            gethostname(deviceName, sizeof(deviceName));
            // 响应报文的格式应该为：TYPE:DISCOVER_RESPONSE DIVICE_NAME:NAME
            char resp[256]={0};
            snprintf(resp,sizeof(resp)-1,"TYPE:DISCOVER_RESPONSE DIVICE_NAME:%s",deviceName);

            if(sendto(sockfd, resp, strlen(resp), 0, (struct sockaddr *)&fromaddr, addrlen)!=strlen(resp))//发送出错，停止读取，然后关闭套接字
            break;
        }
        // 不是探测报文，直接忽略
    }

    close(sockfd);
}

#endif

#endif